import copy
import sys
import os
import shutil
from PyQt5.QtWidgets import *
from pyqtgraph import QtCore, QtGui
from PyQt5.QtWidgets import QPushButton
import os
import configparser
import globalvar
from datetime import timedelta
from datetime import datetime
import multiprocessing
from multiprocessing import Pipe
import time
import importlib
from vnctpmdType661 import *
from PyQt5.QtCore import Qt, pyqtSignal
from pathlib import Path
from multiprocessing import Process, Queue
import numba as nb
global dict_instrumentgroup, dict_instrumentgrouprun
dict_instrumentgroup = {}
dict_instrumentgrouprun = {}
import globalType
import threading
import random
import module_backtestwindow
import threading
import inspect
import ctypes
# 共享内存
import mmap
import contextlib


# 用于回测的虚拟账号父类
class VirtualAccount(object):
    def __init__(self, period, slippoint):
        self.period = period
        self.dict_strategyinstrument = {}
        self.dick_tick = {}
        self.list_tick = []
        self.fee = 0
        self.buyposition = 0
        self.sellposition = 0
        self.slippoint = slippoint
        self.jump = 1
        self.MA_A = 0
        self.MA_B = 0
        self.exchange = 'SHFE'
        # self.InstrumentID
        self.feetype = VN_FEE_RATE
        self.buyvol = 0
        self.sellvol = 0
        self.buyvol_history = 0
        self.sellvol_history = 0
        self.buyprice = 0
        self.sellprice = 0
        self.LastPrice = 0
        self.initamount = 500000
        self.amount = self.initamount
        self.useramount = self.initamount
        self.BidPrice = 0
        self.AskPrice = 0
        self.todayCloseProfit = 0
        self.todayPositionProfit = 0
        self.todayPreBalance = 0
        self.totalfee = 0
        self.buyopennum = 0
        self.sellopennum = 0
        self.buyclosenum = 0
        self.sellclosenum = 0
        self.feetype = VN_FEE_RATE
        self.OpenFee = 0
        self.CloseFee = 0

    #@nb.jit(nogil=True, nopython=True)
    def evaluation(self):
        return [1, 1, 1, 1, 1]

    # 定义合约参数，出现新合约品种可以自己添加，合约代码:[每手吨数*保证金,每手吨数]
    dict_cx = {'rb': [10 * 0.1, 10],
               'RM': [10 * 0.1, 10],
               'ru': [10 * 0.14, 10],
               'SM': [5 * 0.10, 5],
               'CF': [5 * 0.10, 5],
               'zn': [5 * 0.11, 5],
               'al': [5 * 0.09, 5],
               'cu': [5 * 0.14, 5],
               'au': [1000 * 0.12, 1000],
               'ag': [15 * 0.14, 15],
               'hc': [10 * 0.1, 10],
               'bu': [10 * 0.13, 10],
               'ni': [1 * 0.14, 1],
               'i': [100 * 0.11, 100],
               'TA': [5 * 0.12, 5],
               'a': [10 * 0.15, 10],
               'm': [10 * 0.1, 10],
               'y': [10 * 0.1, 10],
               'p': [5 * 0.12, 5],
               'MA': [10 * 0.10, 10],
               'pp': [5 * 0.11, 5],
               'cs': [10 * 0.08, 10],
               'fg': [20 * 0.1, 20],
               'l': [5 * 0.12, 5],
               'v': [5 * 0.12, 5],
               'SR': [10 * 0.10, 10],
               'c': [10 * 0.10, 10],
               'SF': [5 * 0.10, 5],
               'IC': [200 * 0.12, 200],
               'IF': [300 * 0.12, 300],
               'IH': [300 * 0.12, 300],
               'T': [10000 * 0.03, 10000],
               'TF': [10000 * 0.03, 10000],
               'TS': [10000 * 0.03, 10000],
               'j': [100 * 0.15, 100],
               'ZC': [100 * 0.10, 100],
               'jd': [5 * 0.12, 5],
               'AP': [10 * 0.12, 10],
               'sp': [10 * 0.12, 10],
               'CY': [5 * 0.12, 5],
               'BC': [5 * 0.12, 5],
               'CJ': [5 * 0.12, 5],
               'GN': [5 * 0.12, 5],
               'LH': [5 * 0.12, 5],
               'LU': [5 * 0.12, 5],
               'JR': [20 * 0.12, 20],
               'PF': [5 * 0.12, 5],
               'PG': [5 * 0.12, 5],
               'PK': [5 * 0.12, 5],
               'SA': [20 * 0.12, 20],
               'UR': [5 * 0.12, 5],
               'eg': [10 * 0.12, 10]}

    # 获取合约参数
    def GetCX(self, InstrumentID):
        return self.dict_cx[InstrumentID.strip('0123456789')]

    # 用于回测
    def OnKline(self, reportpath1, reportpath2, arg, mddata):
        self.reportpath1 = reportpath1
        self.reportpath2 = reportpath2
        self.arg = arg
        self.TradingDay = mddata.TradingDay
        self.klinetime = mddata.klinetime

    # 保存回测结果到文件
    def AddTradingRecord(self, InstrumentID, ExchangeID, direction, OffsetFlag, OrderPriceType, price, thisvol):
        pathname = '%s/tradingrecord/' % (self.reportpath2)
        filename = '%s/tradingrecord/%d_%d_%d_%d_%d_%d.txt' % (
            self.reportpath2, self.arg[0], self.arg[1], self.arg[2], self.arg[3], self.arg[4], self.arg[5])
        if not Path(self.reportpath1).is_dir():
            os.makedirs(self.reportpath1)
        if not Path(self.reportpath2).is_dir():
            os.makedirs(self.reportpath2)
        if not Path(pathname).is_dir():
            os.makedirs(pathname)
        if direction == '0':
            str1 = '买'
        else:
            str1 = '卖'
        if OffsetFlag == '0':
            str2 = '开仓'
        elif OffsetFlag == '3':
            str2 = '平今'
        elif OffsetFlag == '1':
            str2 = '平仓'
        with open(filename, "a") as file:
            line = '%s,%s,%s,%s,%s,%.2f,%d\n' % (
                self.TradingDay, self.klinetime, InstrumentID, str1, str2, price, thisvol)
            file.write(line)
        file.close()

    # 量化回测用的下单方法
    def InsertOrder_backtest(self, InstrumentID, ExchangeID, direction, OffsetFlag, OrderPriceType, price, thisvol):
        self.AddTradingRecord(InstrumentID, ExchangeID, direction, OffsetFlag, OrderPriceType, price, thisvol)
        # 获得该合约参数
        self.askprice = price
        self.bidprice = price
        self.buyprice = price
        self.sellprice = price
        try:
            c = self.GetCX(self.InstrumentID)
        except Exception as e:
            print('GetCX error:', e)
            return
        cx = c[0]
        cy = c[1]
        self.fee = 0;
        if self.feetype == VN_FEE_RATE:
            # 按比例
            if direction == THOST_FTDC_D_Buy:
                if OffsetFlag == THOST_FTDC_OF_Open:
                    self.fee = self.OpenFee * self.askprice * cy
                else:
                    self.fee = self.CloseFee * self.askprice * cy
            else:
                if OffsetFlag == THOST_FTDC_OF_Open:
                    self.fee = self.OpenFee * self.bidprice * cy
                else:
                    self.fee = self.CloseFee * self.bidprice * cy
        elif self.feetype == VN_FEE_CONSTANT:
            # 固定金额
            if OffsetFlag == THOST_FTDC_OF_Open:
                self.fee = self.OpenFee
            else:
                self.fee = self.CloseFee

        if OffsetFlag == THOST_FTDC_OF_Open:
            allownum = float(thisvol)
            # zmin(thisvol, CalUpdateBigAmount(0, addslip_bidprice, self.useramount, & cx, & cy));
            allownumInt = thisvol
            if direction == THOST_FTDC_D_Buy:
                self.buyopennum += 1
                # printf("买开%d\n", self.buyvol);
                self.addslip_askprice = self.askprice + self.slippoint * self.jump
                cz = float(self.buyvol + allownumInt);
                # 保证有足够的资金开新仓
                if self.useramount - allownum * (self.addslip_askprice * cx + self.fee) > 1e-7:
                    if cz > 1e-7:
                        self.buyprice = (self.buyprice * float(
                            self.buyvol + self.buyvol_history) + self.addslip_askprice * allownum) / cz
                        self.buyvol = self.buyvol + allownumInt;
                        # amount = amount - allownum * fee;
                        self.useramount = self.useramount - allownum * (self.addslip_askprice * cx + self.fee)
                        self.totalfee = self.totalfee + allownum * self.fee
            else:
                self.sellopennum += 1
                # printf("卖开%d\n", self.sellvol);
                self.addslip_bidprice = self.bidprice - self.slippoint * self.jump
                cz = float(self.sellvol + allownumInt)
                # 保证有足够的资金开新仓
                if self.useramount - allownum * (self.addslip_bidprice * cx + self.fee) > 1e-7:
                    if cz > 1e-7:
                        self.sellprice = (self.sellprice * float(
                            self.sellvol + self.sellvol_history) + self.addslip_bidprice * allownum) / cz
                        self.sellvol = self.sellvol + allownumInt
                        # amount = amount - allownum * fee
                        self.useramount = self.useramount - allownum * (self.addslip_bidprice * cx + self.fee)
                        self.totalfee = self.totalfee + allownum * self.fee
        elif OffsetFlag == THOST_FTDC_OF_Close or OffsetFlag == THOST_FTDC_OF_CloseToday:
            # print("z_close\n");
            if direction == THOST_FTDC_D_Buy:
                # print("z_多\n")
                self.buyclosenum += 1
                # 买平，平今
                if OffsetFlag == THOST_FTDC_OF_CloseToday:
                    # print("z_平今[%d>%d]\n", self.sellvol, thisvol);
                    if self.sellvol >= thisvol:
                        # print("z_条件\n");
                        allownum = float(thisvol)
                        allownumInt = thisvol;
                        # 资金曲线，持仓并不是动态的，平仓才earn
                        addslip_askprice = self.askprice + float(self.slippoint) * float(self.jump)
                        thisCloseProfit = allownum * (cy * (self.sellprice - addslip_askprice) - self.fee)
                        self.sellvol = self.sellvol - thisvol;
                        self.useramount = self.useramount + allownum * (self.sellprice * cx) + thisCloseProfit
                        self.totalfee = self.totalfee + allownum * self.fee;
                        # 新增平仓权益计算
                        self.todayCloseProfit = self.todayCloseProfit + thisCloseProfit
                        # 新增持仓权益计算F
                        self.todayPositionProfit = (self.sellprice - price) * float(
                            self.sellvol + self.sellvol_history) + \
                                                   (price - self.buyprice) * float(self.buyvol + self.buyvol_history)
                        if self.sellvol == 0 and self.sellvol_history == 0:
                            self.sellprice = 0;
                    else:
                        pass
                        # 下单失败回调
                else:
                    # print("z_平昨[%d>%d]\n", self.sellvol_history, thisvol)
                    if ExchangeID == "SHFE":
                        # 买平，平仓
                        if self.sellvol_history >= thisvol:
                            allownum = float(thisvol)
                            allownumInt = thisvol
                            # 资金曲线，持仓并不是动态的，平仓才earn
                            self.addslip_askprice = self.askprice + float(self.slippoint) * self.jump
                            # 本次盈利
                            self.thisCloseProfit = allownum * (cy * (self.sellprice - self.addslip_askprice) - self.fee)
                            self.sellvol_history = self.sellvol_history - thisvol
                            self.useramount = self.useramount + allownum * (self.sellprice * cx) + self.thisCloseProfit
                            self.totalfee = self.totalfee + allownum * self.fee
                            # 新增平仓权益计算
                            self.todayCloseProfit = self.todayCloseProfit + self.thisCloseProfit
                            # 新增持仓权益计算F
                            self.todayPositionProfit = (self.sellprice - price) * float(
                                self.sellvol + self.sellvol_history) + \
                                                       (price - self.buyprice) * float(
                                self.buyvol + self.buyvol_history)
                            if self.sellvol == 0 and self.sellvol_history == 0:
                                self.sellprice = 0;
                        else:
                            pass
                            # 下单失败回调
                    else:
                        # 买平，平仓
                        if self.sellvol_history >= thisvol:
                            # print("z_条件\n");
                            allownum = float(thisvol)
                            allownumInt = thisvol
                            # 资金曲线，持仓并不是动态的，平仓才earn
                            self.addslip_askprice = self.askprice + float(self.slippoint) * self.jump
                            self.thisCloseProfit = allownum * (
                                    cy * (self.sellprice - self.addslip_askprice) - self.fee)
                            self.sellvol_history = self.sellvol_history - thisvol
                            self.useramount = self.useramount + allownum * (
                                    self.sellprice * cx) + self.thisCloseProfit
                            self.totalfee = self.totalfee + allownum * self.fee
                            # 新增平仓权益计算
                            self.todayCloseProfit = self.todayCloseProfit + self.thisCloseProfit
                            # 新增持仓权益计算F
                            self.todayPositionProfit = (self.sellprice - price) * float(
                                self.sellvol + self.sellvol_history) + (price - self.buyprice) * float(
                                self.buyvol + self.buyvol_history)
                            if self.sellvol == 0 and self.sellvol_history == 0: self.sellprice = 0;
                        elif self.sellvol >= thisvol:
                            # print("z_条件\n");
                            allownum = float(thisvol);
                            allownumInt = thisvol;
                            # 资金曲线，持仓并不是动态的，平仓才earn
                            self.addslip_askprice = self.askprice + float(self.slippoint) * self.jump
                            self.thisCloseProfit = allownum * (
                                    cy * (self.sellprice - self.addslip_askprice) - self.fee)
                            self.sellvol = self.sellvol - thisvol
                            self.useramount = self.useramount + allownum * (
                                    self.sellprice * cx) + self.thisCloseProfit
                            self.totalfee = self.totalfee + allownum * self.fee
                            # 新增平仓权益计算
                            self.todayCloseProfit = self.todayCloseProfit + self.thisCloseProfit
                            # 新增持仓权益计算F
                            self.todayPositionProfit = (self.sellprice - price) * float(
                                self.sellvol + self.sellvol_history) + \
                                                       (price - self.buyprice) * float(
                                self.buyvol + self.buyvol_history);

                            if self.sellvol == 0 and self.sellvol_history == 0:
                                self.sellprice = 0
                        else:
                            pass
                            # 下单失败回调
            else:
                self.sellclosenum += 1
                if OffsetFlag == THOST_FTDC_OF_CloseToday:
                    # print("z_平今[%d>%d]\n", self.buyvol, thisvol)
                    # 卖平，平今
                    if self.buyvol >= thisvol:
                        # print("z_条件")
                        allownum = float(thisvol)
                        allownumInt = thisvol
                        self.addslip_bidprice = self.bidprice - float(self.slippoint) * self.jump
                        self.thisCloseProfit = allownum * (cy * (self.addslip_bidprice - self.buyprice) - self.fee)
                        self.buyvol = self.buyvol - thisvol
                        self.useramount = self.useramount + allownum * (self.buyprice * cx) + self.thisCloseProfit
                        self.totalfee = self.totalfee + allownum * self.fee
                        # 新增收盘权益计算
                        self.todayCloseProfit = self.todayCloseProfit + self.thisCloseProfit
                        # 新增持仓权益计算F
                        self.todayPositionProfit = (self.sellprice - price) * float(
                            self.sellvol + self.sellvol_history) + (price - self.buyprice) * float(
                            self.buyvol + self.buyvol_history)
                        if self.buyvol == 0 and self.buyvol_history == 0:
                            self.buyprice = 0
                    else:
                        # 下单失败回调
                        pass
                else:
                    # print("z_平昨[%d>%d]\n", self.buyvol_history, thisvol)
                    if ExchangeID == "SHFE":
                        # 卖平，平仓
                        if self.buyvol_history >= thisvol:
                            print("z_条件\n");
                            allownum = float(thisvol);
                            allownumInt = thisvol;
                            addslip_bidprice = self.bidprice - float(self.slippoint) * self.jump;
                            thisCloseProfit = allownum * (cy * (addslip_bidprice - self.buyprice) - self.fee)
                            self.buyvol_history = self.buyvol_history - thisvol
                            self.useramount = self.useramount + allownum * (self.buyprice * cx) + thisCloseProfit
                            self.totalfee = self.totalfee + thisvol * self.fee
                            # 新增收盘权益计算
                            self.todayCloseProfit = self.todayCloseProfit + thisCloseProfit
                            # 新增持仓权益计算F
                            self.todayPositionProfit = (self.sellprice - price) * float(
                                self.sellvol + self.sellvol_history) + (price - self.buyprice) * float(
                                self.buyvol + self.buyvol_history)
                            if self.buyvol == 0 and self.buyvol_history == 0:
                                self.buyprice = 0
                        else:
                            # 下单失败回调
                            pass
                    else:
                        # 卖平，平仓
                        if self.buyvol_history >= thisvol:
                            # print("z_条件\n")
                            allownum = float(thisvol)
                            allownumInt = thisvol;
                            self.addslip_bidprice = self.bidprice - float(self.slippoint) * self.jump
                            self.thisCloseProfit = allownum * (cy * (self.addslip_bidprice - self.buyprice) - self.fee)
                            self.buyvol_history = self.buyvol_history - thisvol;
                            self.useramount = self.useramount + allownum * (self.buyprice * cx) + self.thisCloseProfit
                            self.totalfee = self.totalfee + thisvol * self.fee
                            # 新增收盘权益计算
                            self.todayCloseProfit = self.todayCloseProfit + self.thisCloseProfit
                            # 新增持仓权益计算F
                            self.todayPositionProfit = (self.sellprice - price) * float(
                                self.sellvol + self.sellvol_history) + (price - self.buyprice) * float(
                                self.buyvol + self.buyvol_history)
                            if self.buyvol == 0 and self.buyvol_history == 0:
                                self.buyprice = 0
                        elif self.buyvol >= thisvol:
                            # print("z_条件\n")
                            allownum = float(thisvol)
                            allownumInt = thisvol
                            self.addslip_bidprice = self.bidprice - float(self.slippoint * self.jump)
                            self.thisCloseProfit = allownum * (cy * (self.addslip_bidprice - self.buyprice) - self.fee)
                            self.buyvol = self.buyvol - thisvol
                            self.useramount = self.useramount + allownum * (self.buyprice * cx) + self.thisCloseProfit
                            self.totalfee = self.totalfee + thisvol * self.fee
                            # 新增收盘权益计算
                            self.todayCloseProfit = self.todayCloseProfit + self.thisCloseProfit
                            # 新增持仓权益计算F
                            self.todayPositionProfit = (self.sellprice - price) * float(
                                self.sellvol + self.sellvol_history) + (price - self.buyprice) * float(
                                self.buyvol + self.buyvol_history)
                            if self.buyvol == 0 and self.buyvol_history == 0:
                                self.buyprice = 0
                        else:
                            pass
                            # 下单失败回调

    # 检查是否存储该合约参数的信息，如果没有请自行在 dict_strategyinstrument 添加
    def checkinstrumentID(self, marketdata, strategyname):
        if strategyname in globalvar.dict_strategyinstrument:
            if str(marketdata.InstrumentID, encoding="utf-8") in globalvar.dict_strategyinstrument[strategyname]:
                return 0
            else:
                return 1
        else:
            return 1


# 从文件读取数据文件信息
def Function_ReadDataList(tablename, showcheck):
    for root, dirs, files in os.walk(r"./backtestdata"):
        for name in files:
            if name[len(name) - 4:] != '.csv':
                continue
            print(name)
            # print(os.path.join(root, name))
            row_cnt = tablename.rowCount()  # 返回当前行数（尾部）
            tablename.insertRow(row_cnt)  # 尾部插入一行新行表格
            # for column in range(column_cnt):
            # item = QTableWidgetItem(str(row_cnt + 1))
            # tablename.setItem(row_cnt, 0, item)
            item = QTableWidgetItem(name)
            if showcheck:
                item.setCheckState(QtCore.Qt.Checked)
            tablename.setItem(row_cnt, 1, item)


# 量化回测窗口
class BackTest(object):
    def __init__(self, signal_backtest_processbar, signal_backtest_result, signal_backtest_loaddata,
                 signal_backtest_addresult, signal_backtest_adjustmentprice):
        self.signal_backtest_processbar = signal_backtest_processbar
        self.signal_backtest_result = signal_backtest_result
        self.signal_backtest_loaddata = signal_backtest_loaddata
        self.signal_backtest_addresult = signal_backtest_addresult
        self.signal_backtest_adjustmentprice = signal_backtest_adjustmentprice


# 量化回测线程
class BackTestThread(QtCore.QThread):
    signal_backtest_processbar = pyqtSignal(list)
    signal_backtest_result = pyqtSignal(list)
    signal_backtest_loaddata = pyqtSignal(list)
    signal_backtest_addresult = pyqtSignal(list)
    signal_backtest_adjustmentprice = pyqtSignal(list)

    def __del__(self):
        self.wait()

    def __init__(self):
        super(BackTestThread, self).__init__()
        globalvar.BackTestThreadPoint = self
        # 存储所有参数组合
        self.pardict = {}
        globalvar.DialogBackTestPoint.closestate = False
        self.starttime = 0

    def run(self):
        pass

    class BackTestUpdateResultThread(threading.Thread):
        def __del__(self):
            self.wait()

        def __init__(self):
            super(self).__init__()

        def run(self):
            time.sleep(1)
            globalvar.md.ui = globalvar.ui

    class myThread(threading.Thread):
        def __init__(self, threadID, name, counter, threadLock):
            threading.Thread.__init__(self)
            self.threadID = threadID
            self.name = name
            self.counter = counter
            self.threadLock = threadLock

        def run(self):
            print("开启线程： " + self.name)
            # 获取锁，用于线程同步
            self.threadLock.acquire()
            self.print_time(self.name, self.counter, 3)
            # 释放锁，开启下一个线程
            self.threadLock.release()

        def print_time(self, threadName, delay, counter):
            while counter:
                # time.sleep(delay)
                if threadName == 'Thread-1':
                    globalvar.vnfa.AsynSleep(random.randint(0, 9000))
                else:
                    globalvar.vnfa.AsynSleep(random.randint(0, 1000))
                QApplication.processEvents()
                print("%s: %s" % (threadName, time.ctime(time.time())))
                counter -= 1

    def Initprocess(self, processnum, refreshfrequency, adjustment, slippoint, period, fileid):
        bt = globalvar.BackTestThreadPoint.BackTestThreadMangement(processnum, refreshfrequency)
        bt.RunBackTest(refreshfrequency, adjustment, slippoint, period, fileid)

    # 根据过滤条件，过滤参数组，减少不必要的回测，加快回测进度
    def FilterPar2(self, parnum, conditions0, conditions1, conditions2, value1, value2, value3, value4, value5, value6):
        if parnum == 0 or parnum == 1:
            return True
        elif parnum == 2:
            if conditions0 == '' or conditions0 == '参数条件：不设置':
                return True
            elif conditions0 == '参数条件：参数1<参数2':
                if value1 < value2:
                    return True
                else:
                    return False
            elif conditions0 == '参数条件：参数1>参数2':
                if value1 > value2:
                    return True
                else:
                    return False
        elif parnum == 3:
            add = 0
            if conditions0 == '' or conditions0 == '参数条件：不设置':
                add += 1
            elif conditions0 == '参数条件：参数1<参数2':
                if value1 < value2:
                    add += 1
            elif conditions0 == '参数条件：参数1>参数2':
                if value1 > value2:
                    add += 1
            elif conditions0 == '参数条件：参数1<参数3':
                if value1 < value3:
                    add += 1
            elif conditions0 == '参数条件：参数1>参数3':
                if value1 > value3:
                    add += 1
            elif conditions0 == '参数条件：参数2<参数3':
                if value2 < value3:
                    add += 1
            elif conditions0 == '参数条件：参数2>参数3':
                if value2 > value3:
                    add += 1

            if conditions1 == '' or conditions1 == '参数条件：不设置':
                add += 1
            elif conditions1 == '参数条件：参数1<参数2':
                if value1 < value2:
                    add += 1
            elif conditions1 == '参数条件：参数1>参数2':
                if value1 > value2:
                    add += 1
            elif conditions1 == '参数条件：参数1<参数3':
                if value1 < value3:
                    add += 1
            elif conditions1 == '参数条件：参数1>参数3':
                if value1 > value3:
                    add += 1
            elif conditions1 == '参数条件：参数2<参数3':
                if value2 < value3:
                    add += 1
            elif conditions1 == '参数条件：参数2>参数3':
                if value2 > value3:
                    add += 1
            if add == 2:
                return True
            else:
                return False

        elif parnum >= 4:
            add = 0
            if conditions0 == '' or conditions0 == '参数条件：不设置':
                add += 1
            elif conditions0 == '参数条件：参数1<参数2':
                if value1 < value2:
                    add += 1
            elif conditions0 == '参数条件：参数1>参数2':
                if value1 > value2:
                    add += 1
            elif conditions0 == '参数条件：参数1<参数3':
                if value1 < value3:
                    add += 1
            elif conditions0 == '参数条件：参数1>参数3':
                if value1 > value3:
                    add += 1
            elif conditions0 == '参数条件：参数1<参数4':
                if value1 < value4:
                    add += 1
            elif conditions0 == '参数条件：参数1>参数4':
                if value1 > value4:
                    add += 1
            elif conditions0 == '参数条件：参数2<参数3':
                if value2 < value3:
                    add += 1
            elif conditions0 == '参数条件：参数2>参数3':
                if value2 > value3:
                    add += 1
            elif conditions0 == '参数条件：参数2<参数4':
                if value2 < value4:
                    add += 1
            elif conditions0 == '参数条件：参数2>参数4':
                if value2 > value4:
                    add += 1
            elif conditions0 == '参数条件：参数3<参数4':
                if value3 < value4:
                    add += 1
            elif conditions0 == '参数条件：参数3>参数4':
                if value3 > value4:
                    add += 1

            if conditions1 == '' and conditions1 == '参数条件：不设置':
                add += 1
            elif conditions1 == '参数条件：参数1<参数2':
                if value1 < value2:
                    add += 1
            elif conditions1 == '参数条件：参数1>参数2':
                if value1 > value2:
                    add += 1
            elif conditions1 == '参数条件：参数1<参数3':
                if value1 < value3:
                    add += 1
            elif conditions1 == '参数条件：参数1>参数3':
                if value1 > value3:
                    add += 1
            elif conditions1 == '参数条件：参数1<参数4':
                if value1 < value4:
                    add += 1
            elif conditions1 == '参数条件：参数1>参数4':
                if value1 > value4:
                    add += 1
            elif conditions1 == '参数条件：参数2<参数3':
                if value2 < value3:
                    add += 1
            elif conditions1 == '参数条件：参数2>参数3':
                if value2 > value3:
                    add += 1
            elif conditions1 == '参数条件：参数2<参数4':
                if value2 < value4:
                    add += 1
            elif conditions1 == '参数条件：参数2>参数4':
                if value2 > value4:
                    add += 1
            elif conditions1 == '参数条件：参数3<参数4':
                if value3 < value4:
                    add += 1
            elif conditions1 == '参数条件：参数3>参数4':
                if value3 > value4:
                    add += 1

            if conditions2 == '' and conditions2 == '参数条件：不设置':
                add += 1
            elif conditions2 == '参数条件：参数1<参数2':
                if value1 < value2:
                    add += 1
            elif conditions2 == '参数条件：参数1>参数2':
                if value1 > value2:
                    add += 1
            elif conditions2 == '参数条件：参数1<参数3':
                if value1 < value3:
                    add += 1
            elif conditions2 == '参数条件：参数1>参数3':
                if value1 > value3:
                    add += 1
            elif conditions2 == '参数条件：参数1<参数4':
                if value1 < value4:
                    add += 1
            elif conditions2 == '参数条件：参数1>参数4':
                if value1 > value4:
                    add += 1
            elif conditions2 == '参数条件：参数2<参数3':
                if value2 < value3:
                    add += 1
            elif conditions2 == '参数条件：参数2>参数3':
                if value2 > value3:
                    add += 1
            elif conditions2 == '参数条件：参数2<参数4':
                if value2 < value4:
                    add += 1
            elif conditions2 == '参数条件：参数2>参数4':
                if value2 > value4:
                    add += 1
            elif conditions2 == '参数条件：参数3<参数4':
                if value3 < value4:
                    add += 1
            elif conditions2 == '参数条件：参数3>参数4':
                if value3 > value4:
                    add += 1
            if add == 3:
                return True
            else:
                return False

    def FilterPar(self, parnum, conditions0, conditions1, conditions2, value1, value2, value3, value4, value5, value6):
        returnvalue = self.FilterPar2(parnum, conditions0, conditions1, conditions2, value1, value2, value3, value4,
                                      value5, value6)
        if returnvalue:
            globalvar.totaltasknum += 1
        return returnvalue

    def FilterByFile(self):
        pass

    # 开始量化回测
    def OnStart(self, parnum, refreshfrequency, adjustment, conditions0, conditions1, conditions2):
        globalvar.DialogBackTestPoint.backteststate = True
        globalvar.DialogBackTestPoint.table_lefttop.setEditTriggers(QTableView.NoEditTriggers)
        globalvar.DialogBackTestPoint.btn_ok.setStyleSheet("QPushButton{border-image: url(onstopbacktest1.png)}")
        globalvar.DialogBackTestPoint.btn_ok.setFixedSize(256, 70)
        globalvar.DialogBackTestPoint.list_backtestlog.clear()
        globalvar.DialogBackTestPoint.taskprogressBar.setProperty("value", 0)
        globalvar.DialogBackTestPoint.taskprogressBar.setFormat("参数组回测任务进度 0%")
        globalvar.DialogBackTestPoint.Log("开始测试【" + globalvar.DialogBackTestPoint.strategyname + '】')
        for i in range(globalvar.DialogBackTestPoint.table_leftbottom.rowCount()):
            if globalvar.DialogBackTestPoint.table_leftbottom.item(i, 1).checkState():
                globalvar.DialogBackTestPoint.Log(
                    '将回测：' + globalvar.DialogBackTestPoint.table_leftbottom.item(i, 1).text())

        parnumlist = [0, 0, 0, 0, 0, 0]
        for rowid in range(parnum):
            begin = int(globalvar.DialogBackTestPoint.table_lefttop.item(rowid, 1).text())
            end = int(globalvar.DialogBackTestPoint.table_lefttop.item(rowid, 2).text())
            step = int(globalvar.DialogBackTestPoint.table_lefttop.item(rowid, 3).text())
            parnumlist[rowid] = (end - begin + 1) / max(1, step)

        globalvar.totaltasknum = 0
        globalvar.finishtasknum = 0
        self.pardict.clear()
        self.pardict = {}
        globalvar.DialogBackTestPoint.Log('回测选项：' + globalvar.DialogBackTestPoint.comBox_process.currentText())
        globalvar.DialogBackTestPoint.Log('待回测参数组：【' + str(globalvar.totaltasknum) + '】个')
        slippoint = globalvar.DialogBackTestPoint.comBox_slippoint.currentIndex() + 1
        period = globalvar.DialogBackTestPoint.comBox_period.currentText()
        if globalvar.DialogBackTestPoint.table_lefttop.item(0, 1):
            for parnumlist[0] in range(int(globalvar.DialogBackTestPoint.table_lefttop.item(0, 1).text()),
                                       int(globalvar.DialogBackTestPoint.table_lefttop.item(0, 2).text()) + 1,
                                       int(globalvar.DialogBackTestPoint.table_lefttop.item(0, 3).text())):
                if globalvar.DialogBackTestPoint.table_lefttop.item(1, 1):
                    for parnumlist[1] in range(int(globalvar.DialogBackTestPoint.table_lefttop.item(1, 1).text()),
                                               int(globalvar.DialogBackTestPoint.table_lefttop.item(1, 2).text()) + 1,
                                               int(globalvar.DialogBackTestPoint.table_lefttop.item(1, 3).text())):
                        if globalvar.DialogBackTestPoint.table_lefttop.item(2, 1):
                            for parnumlist[2] in range(
                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(2, 1).text()),
                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(2, 2).text()) + 1,
                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(2, 3).text())):
                                if globalvar.DialogBackTestPoint.table_lefttop.item(3, 1):
                                    for parnumlist[3] in range(
                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(3, 1).text()),
                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(3, 2).text()) + 1,
                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(3, 3).text())):
                                        if globalvar.DialogBackTestPoint.table_lefttop.item(4, 1):
                                            for parnumlist[4] in range(
                                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(4, 1).text()),
                                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(4,
                                                                                                         2).text()) + 1,
                                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(4, 3).text())):
                                                if globalvar.DialogBackTestPoint.table_lefttop.item(5, 1):
                                                    for parnumlist[5] in range(
                                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(5,
                                                                                                                 1).text()),
                                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(5,
                                                                                                                 2).text()) + 1,
                                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(5,
                                                                                                                 3).text())):
                                                        if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                                                          parnumlist[0],
                                                                          parnumlist[1], parnumlist[2], parnumlist[3],
                                                                          parnumlist[4], parnumlist[5]):
                                                            self.pardict['%d,%d,%d,%d,%d,%d' % (
                                                                parnumlist[0], parnumlist[1], parnumlist[2],
                                                                parnumlist[3],
                                                                parnumlist[4], parnumlist[5])] = False
                                                else:
                                                    if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                                                      parnumlist[0],
                                                                      parnumlist[1], parnumlist[2], parnumlist[3],
                                                                      parnumlist[4], parnumlist[5]):
                                                        self.pardict['%d,%d,%d,%d,%d,%d' % (
                                                            parnumlist[0], parnumlist[1], parnumlist[2],
                                                            parnumlist[3],
                                                            parnumlist[4], parnumlist[5])] = False
                                        else:
                                            if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                                              parnumlist[0],
                                                              parnumlist[1], parnumlist[2], parnumlist[3],
                                                              parnumlist[4], parnumlist[5]):
                                                self.pardict['%d,%d,%d,%d,%d,%d' % (
                                                    parnumlist[0], parnumlist[1], parnumlist[2],
                                                    parnumlist[3],
                                                    parnumlist[4], parnumlist[5])] = False
                                else:
                                    if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                                      parnumlist[0],
                                                      parnumlist[1], parnumlist[2], parnumlist[3],
                                                      parnumlist[4], parnumlist[5]):
                                        self.pardict['%d,%d,%d,%d,%d,%d' % (
                                            parnumlist[0], parnumlist[1], parnumlist[2],
                                            parnumlist[3],
                                            parnumlist[4], parnumlist[5])] = False
                        else:
                            if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                              parnumlist[0],
                                              parnumlist[1], parnumlist[2], parnumlist[3],
                                              parnumlist[4], parnumlist[5]):
                                self.pardict['%d,%d,%d,%d,%d,%d' % (
                                    parnumlist[0], parnumlist[1], parnumlist[2],
                                    parnumlist[3],
                                    parnumlist[4], parnumlist[5])] = False
                else:
                    if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                      parnumlist[0],
                                      parnumlist[1], parnumlist[2], parnumlist[3],
                                      parnumlist[4], parnumlist[5]):
                        self.pardict['%d,%d,%d,%d,%d,%d' % (
                            parnumlist[0], parnumlist[1], parnumlist[2],
                            parnumlist[3],
                            parnumlist[4], parnumlist[5])] = False
        else:
            if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                              parnumlist[0],
                              parnumlist[1], parnumlist[2], parnumlist[3],
                              parnumlist[4], parnumlist[5]):
                self.pardict['%d,%d,%d,%d,%d,%d' % (
                    parnumlist[0], parnumlist[1], parnumlist[2],
                    parnumlist[3],
                    parnumlist[4], parnumlist[5])] = False

        processnum = min(globalvar.DialogBackTestPoint.comBox_process.currentIndex() + 1, globalvar.totaltasknum)
        print('processnum: ' + str(processnum))
        print('refreshfrequency' + str(refreshfrequency))
        globalvar.DialogBackTestPoint.Log('实际开启【' + str(processnum) + '】个进程')
        globalvar.DialogBackTestPoint.Log('提示：正在升级本回测模块')
        globalvar.DialogBackTestPoint.table_thispargroup.clear()
        globalvar.DialogBackTestPoint.table_thispargroup.setRowCount(0)
        globalvar.DialogBackTestPoint.table_thispargroup.setHorizontalHeaderLabels(
            ['', '参数1', '参数2', '参数3', '参数4', '参数5', '参数6', '权益', '收益率', '胜率', '盈亏比', '交易次数', '夏普率'])
        self.Initprocess(processnum, refreshfrequency, adjustment, slippoint, period, 0)

    # 继续执行下一个合约的量化回测
    def OnStartNext(self, parnum, refreshfrequency, adjustment, conditions0, conditions1, conditions2, fileid):
        globalvar.DialogBackTestPoint.backteststate = True
        globalvar.DialogBackTestPoint.table_lefttop.setEditTriggers(QTableView.NoEditTriggers)
        globalvar.DialogBackTestPoint.btn_ok.setStyleSheet("QPushButton{border-image: url(onstopbacktest1.png)}")
        globalvar.DialogBackTestPoint.btn_ok.setFixedSize(256, 70)
        globalvar.DialogBackTestPoint.list_backtestlog.clear()
        globalvar.DialogBackTestPoint.taskprogressBar.setProperty("value", 0)
        globalvar.DialogBackTestPoint.taskprogressBar.setFormat("参数组回测任务进度 0%")
        globalvar.DialogBackTestPoint.Log("开始测试【" + globalvar.DialogBackTestPoint.strategyname + '】')
        for i in range(globalvar.DialogBackTestPoint.table_leftbottom.rowCount()):
            if globalvar.DialogBackTestPoint.table_leftbottom.item(i, 1).checkState():
                '''try:
                    globalvar.DialogBackTestPoint.Log(
                        '将回测：' + globalvar.DialogBackTestPoint.table_leftbottom.item(i,
                                                                                     1).text() + ' ,时间段：' + globalvar.DialogBackTestPoint.table_leftbottom.item(
                            i, 2).text() + '~' + globalvar.DialogBackTestPoint.table_leftbottom.item(i, 3).text())
                except os.error:
                '''
                globalvar.DialogBackTestPoint.Log(
                    '将回测：' + globalvar.DialogBackTestPoint.table_leftbottom.item(i, 1).text())
        parnumlist = [0, 0, 0, 0, 0, 0]
        for rowid in range(parnum):
            begin = int(globalvar.DialogBackTestPoint.table_lefttop.item(rowid, 1).text())
            end = int(globalvar.DialogBackTestPoint.table_lefttop.item(rowid, 2).text())
            step = int(globalvar.DialogBackTestPoint.table_lefttop.item(rowid, 3).text())
            parnumlist[rowid] = (end - begin + 1) / max(1, step)

        globalvar.totaltasknum = 0
        globalvar.finishtasknum = 0
        self.pardict.clear()
        self.pardict = {}
        globalvar.DialogBackTestPoint.Log('回测选项：' + globalvar.DialogBackTestPoint.comBox_process.currentText())
        globalvar.DialogBackTestPoint.Log('待回测参数组：【' + str(globalvar.totaltasknum) + '】个')
        slippoint = globalvar.DialogBackTestPoint.comBox_slippoint.currentIndex() + 1
        period = globalvar.DialogBackTestPoint.comBox_period.currentText()
        if globalvar.DialogBackTestPoint.table_lefttop.item(0, 1):
            for parnumlist[0] in range(int(globalvar.DialogBackTestPoint.table_lefttop.item(0, 1).text()),
                                       int(globalvar.DialogBackTestPoint.table_lefttop.item(0, 2).text()) + 1,
                                       int(globalvar.DialogBackTestPoint.table_lefttop.item(0, 3).text())):
                if globalvar.DialogBackTestPoint.table_lefttop.item(1, 1):
                    for parnumlist[1] in range(int(globalvar.DialogBackTestPoint.table_lefttop.item(1, 1).text()),
                                               int(globalvar.DialogBackTestPoint.table_lefttop.item(1, 2).text()) + 1,
                                               int(globalvar.DialogBackTestPoint.table_lefttop.item(1, 3).text())):
                        if globalvar.DialogBackTestPoint.table_lefttop.item(2, 1):
                            for parnumlist[2] in range(
                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(2, 1).text()),
                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(2, 2).text()) + 1,
                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(2, 3).text())):
                                if globalvar.DialogBackTestPoint.table_lefttop.item(3, 1):
                                    for parnumlist[3] in range(
                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(3, 1).text()),
                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(3, 2).text()) + 1,
                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(3, 3).text())):
                                        if globalvar.DialogBackTestPoint.table_lefttop.item(4, 1):
                                            for parnumlist[4] in range(
                                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(4, 1).text()),
                                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(4,
                                                                                                         2).text()) + 1,
                                                    int(globalvar.DialogBackTestPoint.table_lefttop.item(4, 3).text())):
                                                if globalvar.DialogBackTestPoint.table_lefttop.item(5, 1):
                                                    for parnumlist[5] in range(
                                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(5,
                                                                                                                 1).text()),
                                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(5,
                                                                                                                 2).text()) + 1,
                                                            int(globalvar.DialogBackTestPoint.table_lefttop.item(5,
                                                                                                                 3).text())):
                                                        if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                                                          parnumlist[0],
                                                                          parnumlist[1], parnumlist[2], parnumlist[3],
                                                                          parnumlist[4], parnumlist[5]):
                                                            self.pardict['%d,%d,%d,%d,%d,%d' % (
                                                                parnumlist[0], parnumlist[1], parnumlist[2],
                                                                parnumlist[3],
                                                                parnumlist[4], parnumlist[5])] = False


                                                else:
                                                    if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                                                      parnumlist[0],
                                                                      parnumlist[1], parnumlist[2], parnumlist[3],
                                                                      parnumlist[4], parnumlist[5]):
                                                        self.pardict['%d,%d,%d,%d,%d,%d' % (
                                                            parnumlist[0], parnumlist[1], parnumlist[2],
                                                            parnumlist[3],
                                                            parnumlist[4], parnumlist[5])] = False

                                        else:
                                            if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                                              parnumlist[0],
                                                              parnumlist[1], parnumlist[2], parnumlist[3],
                                                              parnumlist[4], parnumlist[5]):
                                                self.pardict['%d,%d,%d,%d,%d,%d' % (
                                                    parnumlist[0], parnumlist[1], parnumlist[2],
                                                    parnumlist[3],
                                                    parnumlist[4], parnumlist[5])] = False

                                else:
                                    if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                                      parnumlist[0],
                                                      parnumlist[1], parnumlist[2], parnumlist[3],
                                                      parnumlist[4], parnumlist[5]):
                                        self.pardict['%d,%d,%d,%d,%d,%d' % (
                                            parnumlist[0], parnumlist[1], parnumlist[2],
                                            parnumlist[3],
                                            parnumlist[4], parnumlist[5])] = False

                        else:
                            if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                              parnumlist[0],
                                              parnumlist[1], parnumlist[2], parnumlist[3],
                                              parnumlist[4], parnumlist[5]):
                                self.pardict['%d,%d,%d,%d,%d,%d' % (
                                    parnumlist[0], parnumlist[1], parnumlist[2],
                                    parnumlist[3],
                                    parnumlist[4], parnumlist[5])] = False
                else:
                    if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                                      parnumlist[0],
                                      parnumlist[1], parnumlist[2], parnumlist[3],
                                      parnumlist[4], parnumlist[5]):
                        self.pardict['%d,%d,%d,%d,%d,%d' % (
                            parnumlist[0], parnumlist[1], parnumlist[2],
                            parnumlist[3],
                            parnumlist[4], parnumlist[5])] = False
        else:
            if self.FilterPar(parnum, conditions0, conditions1, conditions2,
                              parnumlist[0],
                              parnumlist[1], parnumlist[2], parnumlist[3],
                              parnumlist[4], parnumlist[5]):
                self.pardict['%d,%d,%d,%d,%d,%d' % (
                    parnumlist[0], parnumlist[1], parnumlist[2],
                    parnumlist[3],
                    parnumlist[4], parnumlist[5])] = False

        processnum = min(globalvar.DialogBackTestPoint.comBox_process.currentIndex() + 1, globalvar.totaltasknum)
        print('processnum: ' + str(processnum))
        globalvar.DialogBackTestPoint.Log('实际开启【' + str(processnum) + '】个进程')
        globalvar.DialogBackTestPoint.Log('提示：正在升级本回测模块')
        globalvar.DialogBackTestPoint.table_thispargroup.clear()
        globalvar.DialogBackTestPoint.table_thispargroup.setRowCount(0)
        globalvar.DialogBackTestPoint.table_thispargroup.setHorizontalHeaderLabels(
            ['', '参数1', '参数2', '参数3', '参数4', '参数5', '参数6', '权益', '收益率', '胜率', '盈亏比', '交易次数', '夏普率'])
        self.Initprocess(processnum, refreshfrequency, adjustment, slippoint, period, fileid)

    # 停止量化回测
    def OnStop(self, text):
        globalvar.DialogBackTestPoint.closestate = True
        globalvar.DialogBackTestPoint.backteststate = False
        globalvar.DialogBackTestPoint.table_lefttop.setEditTriggers(QTableView.CurrentChanged)
        if text == '完成回测':
            globalvar.DialogBackTestPoint.btn_ok.setStyleSheet("QPushButton{border-image: url(onrestartbacktest1.png)}")
            globalvar.DialogBackTestPoint.btn_ok.setFixedSize(256, 70)
        else:
            globalvar.DialogBackTestPoint.btn_ok.setStyleSheet("QPushButton{border-image: url(onstartbacktest1.png)}")
            globalvar.DialogBackTestPoint.btn_ok.setFixedSize(256, 70)

        globalvar.DialogBackTestPoint.Log(text + "【" + globalvar.DialogBackTestPoint.strategyname + '】')

    def OnStopAndNext(self, fileid):
        # globalvar.DialogBackTestPoint.callback_backtest_processbar([0, '数据载入进度%p%'])
        globalvar.DialogBackTestPoint.closestate = True
        globalvar.DialogBackTestPoint.backteststate = False
        globalvar.DialogBackTestPoint.OnCloseProcesswindow()
        globalvar.pool.close()
        globalvar.pool.terminate()
        globalvar.DialogBackTestPoint.OnStart_Next(fileid)

    class BackTestThreadMangement(object):
        def __init__(self, processnum, refreshfrequency):
            super().__init__()
            self.processnum = processnum
            self.refreshfrequency = refreshfrequency
            # 进程进度条ID
            self.barid = 0
            self.memorydatalist = []
            self.list_backtestfile = []
            self.lastinsurumentid = 0
            self.fileidadd = 0
            self.dict_p = {'M1': 1,
                           'M3': 3,
                           'M5': 5,
                           'M10': 10,
                           'M15': 15,
                           'M30': 30,
                           'M60': 60,
                           'M120': 120,
                           'D1': 9999, }

            globalvar.manager = multiprocessing.Manager()
            # 父进程创建Queue，并传给各个子进程：
            globalvar.q = globalvar.manager.Queue()

        def dynamic_import(self, module):
            return importlib.import_module(module)

        def StrategyCalculate_Virtualapi(self, arg):
            return [arg, arg[0] + arg[1] + arg[2] + arg[3], 2.3, 0.5]

        # 取最小值，但需忽略无效值0的影响
        #@nb.jit(nogil=True, nopython=True)
        def z_min(self, a, b):
            if a < 1e-7:
                return b
            elif b < 1e-7:
                return a
            else:
                return min(a, b)

        # 主力合约差值前复权,根据最后一个字段合约名称判断，通过收盘价和开盘价差，计算复权因子进行复权
        def AdjustmentPrice_Backward(self, filesize):
            firstline = True
            memorydatalist2 = []
            linenumadd = 0
            byteadd = 0
            instrumentID_last = ''
            closeprice_last = 0
            diffprice = 0
            for line in self.memorydatalist:
                if globalvar.DialogBackTestPoint.closestate:
                    break
                # if not globalvar.DialogBackTestPoint.backteststate:
                #    break
                globalvar.vnfa.AsynSleep(0)
                QApplication.processEvents()
                if firstline:
                    firstline = False
                else:
                    mdarr = line.strip('\n').split(',')
                    instrumentID = mdarr[8]
                    if instrumentID_last != instrumentID:
                        diffprice = diffprice + float(mdarr[2]) - closeprice_last
                        combineddata = mdarr[0] + ',' + str(float(mdarr[1]) + diffprice) + ',' + str(
                            float(mdarr[2]) + diffprice) + ',' + str(float(mdarr[3]) + diffprice) + ',' + str(
                            float(mdarr[4]) + diffprice) + ',' + mdarr[5] + ',' + mdarr[6] + ',' + mdarr[7] + ',' + \
                                       mdarr[8]
                        memorydatalist2.append(combineddata)
                        closeprice_last = float(mdarr[4])
                        instrumentID_last = instrumentID
                    else:
                        memorydatalist2.append(line)
                linenumadd += 1
                byteadd = byteadd + len(line) + 1
                globalvar.DialogBackTestPoint.bt.signal_backtest_adjustmentprice.emit(
                    [linenumadd, byteadd / filesize, '后复权'])
            self.memorydatalist = copy.deepcopy(memorydatalist2)

        # 主力合约差值后复权
        def AdjustmentPrice_Forward(self, filesize):
            firstline = True
            memorydatalist2 = []
            linenumadd = 0
            byteadd = 0
            instrumentID_last = ''
            closeprice_last = 0
            diffprice = 0
            for line in self.memorydatalist:
                if globalvar.DialogBackTestPoint.closestate:
                    break
                # if not globalvar.DialogBackTestPoint.backteststate:
                #    break
                globalvar.vnfa.AsynSleep(0)
                QApplication.processEvents()
                if firstline:
                    firstline = False
                else:
                    mdarr = line.strip('\n').split(',')
                    instrumentID = mdarr[8]
                    if instrumentID_last != instrumentID:
                        diffprice = diffprice + float(mdarr[2]) - closeprice_last
                        combineddata = mdarr[0] + ',' + str(float(mdarr[1]) + diffprice) + ',' + str(
                            float(mdarr[2]) + diffprice) + ',' + str(float(mdarr[3]) + diffprice) + ',' + str(
                            float(mdarr[4]) + diffprice) + ',' + mdarr[5] + ',' + mdarr[6] + ',' + mdarr[7] + ',' + \
                                       mdarr[8]
                        memorydatalist2.append(combineddata)
                        closeprice_last = float(mdarr[4])
                        instrumentID_last = instrumentID
                    else:
                        memorydatalist2.append(line)
                linenumadd += 1
                byteadd = byteadd + len(line) + 1
                globalvar.DialogBackTestPoint.bt.signal_backtest_adjustmentprice.emit(
                    [linenumadd, byteadd / filesize, '前复权'])
            self.memorydatalist = copy.deepcopy(memorydatalist2)

        def CombinedKlineData(self, period, filesize):
            firstline = True
            kline = VNKlineData()
            memorydatalist2 = []
            linenumadd = 0
            byteadd = 0
            for line in self.memorydatalist:
                if globalvar.DialogBackTestPoint.closestate:
                    break
                # if not globalvar.DialogBackTestPoint.backteststate:
                #    break
                globalvar.vnfa.AsynSleep(0)
                QApplication.processEvents()
                if firstline:
                    firstline = False
                else:
                    mdarr = line.strip('\n').split(',')
                    thistime = datetime.strptime(str(mdarr[0]), "%Y-%m-%d %H:%M:%S")
                    TradingDay = int(thistime.strftime("%Y%m%d"))
                    klinetime = int(thistime.strftime("%H%M%S"))
                    minute = int(thistime.strftime("%M"))
                    if minute % self.dict_p[period] == 0:
                        combineddata = str(mdarr[0]) + ',' + \
                                       str(kline.open) + ',' + \
                                       str(kline.high) + ',' + \
                                       str(kline.low) + ',' + \
                                       str(kline.close) + ',' + \
                                       str(kline.volume) + ',' + \
                                       str(kline.money) + ',' + \
                                       str(kline.open_interest) + ',' + \
                                       str(kline.InstrumentID.decode())
                        memorydatalist2.append(combineddata)
                        kline = VNKlineData()
                        kline.TradingDay = TradingDay
                        kline.klinetime = klinetime
                        kline.open = float(mdarr[1])
                        kline.high = max(kline.high, float(mdarr[2]))
                        kline.low = self.z_min(kline.low, float(mdarr[3]))
                        kline.close = float(mdarr[4])
                        kline.volume = kline.volume + int(float(mdarr[5]))
                        kline.money = kline.money + float(mdarr[6])
                        kline.open_interest = float(mdarr[7])
                        kline.InstrumentID = mdarr[8].encode('utf-8')
                    else:
                        kline.TradingDay = TradingDay
                        kline.klinetime = klinetime
                        kline.open = float(mdarr[1])
                        kline.high = max(kline.high, float(mdarr[2]))
                        kline.low = self.z_min(kline.low, float(mdarr[3]))
                        kline.close = float(mdarr[4])
                        kline.volume = kline.volume + int(float(mdarr[5]))
                        kline.money = kline.money + float(mdarr[6])
                        kline.open_interest = float(mdarr[7])
                        kline.InstrumentID = mdarr[8].encode('utf-8')
                linenumadd += 1
                byteadd = byteadd + len(line) + 1
                # if linenumadd%10==0:
                globalvar.DialogBackTestPoint.bt.signal_backtest_loaddata.emit(
                    [2, linenumadd, float(byteadd) / float(filesize), period])
            self.memorydatalist = copy.deepcopy(memorydatalist2)

        # 资金曲线
        def GenerateBackTestEquityCurve(self, TradingDay, TradeingTime, useramount):
            line = '%s,%s,%s\n' % (TradingDay, TradeingTime, str(useramount))
            self.list_backtestfile.append(line)

        def WirteBackTestEquityCurve(self, path, path2, arg):
            if not Path(path).is_dir():
                os.makedirs(path)
            if not Path(path2).is_dir():
                os.makedirs(path2)
            with open('%s/%d_%d_%d_%d_%d_%d.txt' % (path2, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]),
                      "a") as file:
                for i in range(len(self.list_backtestfile)):
                    QApplication.processEvents()
                    globalvar.vnfa.AsynSleep(0)
                    file.write(self.list_backtestfile[i])
            file.close()

        # 读取文件后从内存读取
        def StrategyCalculate_memory(self, strategyname, mainstrategyname, reportpath1, reportpath2, arg,
                                     refreshfrequency,
                                     splipoint, period, csvfile, linenum, instrumentid, q):
            # 参数，夏普率，胜率
            module = self.dynamic_import('strategyfilebacktest.' + mainstrategyname)
            ms = module.MyStrategy(period, splipoint)
            firstline = True
            readlinenum = 0
            byteadd = 0
            timepath = reportpath1
            self.list_backtestfile = []
            fileinfo = os.stat(csvfile)

            for line in self.memorydatalist:
                globalvar.vnfa.AsynSleep(0)
                QApplication.processEvents()
                byteadd = byteadd + len(line) + 1

                if readlinenum % refreshfrequency == 0:
                    percent = '%.2f' % (float(100 * byteadd) / float(fileinfo.st_size))
                    print(str(arg) + '(' + percent + '%)' + line)
                if readlinenum % 200 == 0:
                    # q.put(datetime.now(), False)
                    # self.readlasttime = datetime.now()
                    try:
                        # 可以使用put_nowait，如果队列满了不会阻塞，但是会因为队列满了而报错
                        # 因此我们可以用一个try语句来处理这个错误。这样程序不会一直阻塞下去，但是会丢掉这个消息
                        q.put_nowait([instrumentid, datetime.now(), reportpath2.split('/')[2]])
                        # q.put_nowait(instrumentid)
                    except:
                        # 队列已经满了
                        pass

                globalvar.vnfa.AsynSleep(0)
                QApplication.processEvents()
                if firstline:
                    firstline = False
                else:
                    mdarr = line.strip('\n').split(',')
                    thistime = datetime.strptime(str(mdarr[0]), "%Y-%m-%d %H:%M:%S")
                    TradingDay = int(thistime.strftime("%Y%m%d"))
                    klinetime = int(thistime.strftime("%H%M%S"))
                    kline = VNKlineData()
                    kline.TradingDay = TradingDay
                    kline.klinetime = klinetime
                    kline.open = float(mdarr[1])
                    kline.high = float(mdarr[2])
                    kline.low = float(mdarr[3])
                    kline.close = float(mdarr[4])
                    kline.volume = int(float(mdarr[5]))
                    kline.money = float(mdarr[6])
                    kline.open_interest = float(mdarr[7])
                    kline.InstrumentID = mdarr[8].encode('utf-8')
                    ms.OnKline(reportpath1, reportpath2, kline, arg, strategyname)
                    self.GenerateBackTestEquityCurve(TradingDay, klinetime, ms.useramount)
                readlinenum += 1
            self.WirteBackTestEquityCurve(reportpath1, reportpath2, arg)
            return [arg, [ms.useramount, 100 * (ms.useramount - ms.initamount) / ms.initamount,
                          ms.buyopennum, ms.sellopennum, ms.buyclosenum, ms.sellclosenum], reportpath2, instrumentid]

        # 每次回测从文件读取
        def StrategyCalculate_file(self, strategyname, mainstrategyname, reportpath1, reportpath2, arg,
                                   splipoint, period, csvfile):
            # https://blog.csdn.net/qq_40250862/article/details/81215293
            # 参数，夏普率，胜率
            module = self.dynamic_import('strategyfilebacktest.' + mainstrategyname)
            ms = module.MyStrategy(period, splipoint)
            firstline = True
            linenum = 0
            readlinenum = 0
            with open(csvfile, 'r') as f:
                for line in f:
                    globalvar.vnfa.AsynSleep(0)
                    QApplication.processEvents()
                    linenum += 1
            list_backtestfile = []
            with open(csvfile, 'r') as f:
                for line in f:
                    globalvar.vnfa.AsynSleep(0)
                    QApplication.processEvents()
                    if firstline:
                        firstline = False
                    else:
                        mdarr = line.strip('\n').split(',')
                        thistime = datetime.strptime(str(mdarr[0]), "%Y-%m-%d %H:%M:%S")
                        TradingDay = int(thistime.strftime("%Y%m%d"))
                        klinetime = int(thistime.strftime("%H%M%S"))
                        kline = VNKlineData()
                        kline.TradingDay = TradingDay  # mdarr[0][0:9].encode('utf-8')
                        kline.klinetime = klinetime  # mdarr[0][11:18].encode('utf-8')
                        kline.open = float(mdarr[1])
                        kline.high = float(mdarr[2])
                        kline.low = float(mdarr[3])
                        kline.close = float(mdarr[4])
                        kline.volume = int(float(mdarr[5]))
                        kline.money = float(mdarr[6])
                        kline.open_interest = float(mdarr[7])
                        kline.InstrumentID = mdarr[8].encode('utf-8')
                        ms.OnKline(kline, arg, strategyname)

                    self.GenerateBackTestEquityCurve(list_backtestfile, reportpath2, TradingDay, klinetime,
                                                     mainstrategyname, arg, ms.useramount,
                                                     ms.initamount)

                    readlinenum += 1
            self.WirteBackTestEquityCurve(list_backtestfile, reportpath1, reportpath2, arg)
            return [arg, [ms.useramount, 100 * (ms.useramount - ms.initamount) / ms.initamount,
                          ms.buyopennum, ms.sellopennum, ms.buyclosenum, ms.sellclosenum], reportpath2]

        def StrategyCalculate(self, strategyname, mainstrategyname, reportpath1, reportpath2, arg, refreshfrequency,
                              slippoint,
                              period, csvfile, linenum, instrumentid, q):
            if True:
                # python简单读取文件模式回测
                return self.StrategyCalculate_memory(strategyname, mainstrategyname, reportpath1, reportpath2, arg,
                                                     refreshfrequency,
                                                     slippoint, period, csvfile, linenum, instrumentid, q)
            elif True:
                return self.StrategyCalculate_file(strategyname, mainstrategyname, reportpath1, reportpath2, arg,
                                                   splipoint, period, csvfile)
            else:
                # 仿真回测, 暂不支持
                return self.StrategyCalculate_Virtualapi(arg)

        def BackTestProcess(self, strategyname, mainstrategyname, reportpath1, reportpath2, arg, refreshfrequency,
                            slippoint, period,
                            csvfile, linenum, instrumentid, q):
            QApplication.processEvents()
            time.sleep(0)
            result = self.StrategyCalculate(strategyname, mainstrategyname, reportpath1, reportpath2, arg,
                                            refreshfrequency, slippoint,
                                            period, csvfile, linenum, instrumentid, q)
            diffsecond = (datetime.now() - self.starttime).seconds
            print('进程: %s' % (result))

            # 进程: [[3, 15, 0, 0, 0, 0], [452372.0, -9.5256, 592, 592, 592, 582],'backtestreport/talib_MA/202112250620/rb9999.XSGE.csv', 0]
            return [result, diffsecond, os.getpid()]

        #@nb.jit(nogil=True, nopython=True)
        def waitsleep(self):
            globalvar.vnfa.AsynSleep(1)
            time.sleep(0)
            # QApplication.processEvents()

        def RunAgain(self, arg):
            instrumentid = arg[0]
            now = arg[1]
            print('----RunAgain[%s,%s]----' % (instrumentid, self.lastinsurumentid))
            try:
                if instrumentid == self.lastinsurumentid:
                    print('完成回测')
                    globalvar.BackTestThreadPoint.OnStop('完成回测')
                else:
                    print('下一个合约')
                    unfinish = False
                    for key in globalvar.BackTestThreadPoint.pardict.keys():
                        if globalvar.BackTestThreadPoint.pardict[key]:
                            continue
                        unfinish = True
                    if unfinish:
                        self.RunBackTestAgain(self.refreshfrequency, self.adjustment, self.slippoint,
                                              self.period, instrumentid, now)
                    else:
                        globalvar.DialogBackTestPoint.OnCloseProcesswindow()
                        globalvar.pool.close()
                        globalvar.pool.terminate()
                        globalvar.BackTestThreadPoint.OnStopAndNext(instrumentid + 1)
            except Exception as e:
                print('RunAgain error:', e)

        def CallRusult(self, result):
            t1 = str(result[0][0][0]) + ',' + str(result[0][0][1]) + ',' + str(result[0][0][2]) + ',' + str(
                result[0][0][3]) + ',' + str(result[0][0][4]) + ',' + str(result[0][0][5])
            t2 = str(result[0][1][0]) + ',' + str(result[0][1][1]) + ',' + str(result[0][1][2]) + ',' + str(
                result[0][1][3]) + ',' + str(result[0][1][4]) + ',' + str(result[0][1][5])
            globalvar.BackTestThreadPoint.pardict[t1] = True
            # 进程: [[3, 15, 0, 0, 0, 0], [452372.0, -9.5256, 592, 592, 592, 582],'backtestreport/talib_MA/202112250620/rb9999.XSGE.csv', 0]

            globalvar.finishtasknum += 1
            globalvar.DialogBackTestPoint.bt.signal_backtest_result.emit(result)
            list = result[0][2].split('/')
            # print('list: '+str(list))

            indexpath = list[0] + '/' + list[1] + '/' + list[2] + '/' + 'resultlist.csv'

            with open('%s' % (indexpath),
                      "a") as file:
                file.write(t1 + ',' + t2 + '\n')
            if globalvar.finishtasknum == globalvar.totaltasknum:
                if globalvar.DialogBackTestPoint.closestate == False:
                    globalvar.DialogBackTestPoint.closestate = True
                    globalvar.DialogBackTestPoint.backteststate = True
                    globalvar.DialogBackTestPoint.table_lefttop.setEditTriggers(QTableView.CurrentChanged)
                    # print(str(globalvar.totaltasknum))
                    globalvar.DialogBackTestPoint.bt.signal_backtest_addresult.emit(result)
                    print('result: ' + str(result))
                # globalvar.pool.terminate()

        def CleanDir(self, dir):
            if os.path.isdir(dir):
                paths = os.listdir(dir)
                for path in paths:
                    filePath = os.path.join(dir, path)
                    if os.path.isfile(filePath):
                        try:
                            os.remove(filePath)
                        except os.error:
                            print("remove %s error." % filePath)  # 引入logging
                    elif os.path.isdir(filePath):
                        if filePath[-4:].lower() == ".svn".lower():
                            continue
                        shutil.rmtree(filePath, True)
            return True

        # 读数据进程执行的代码：
        def ProcessWinThread(self):
            try:
                app = module_backtestwindow.QtWidgets.QApplication(sys.argv)
                # app.aboutToQuit.connect(app.deleteLater)
                app.setStyleSheet(module_backtestwindow.qdarkstyle.load_stylesheet_pyqt5())
                globalvar.gui = module_backtestwindow.MainUi(200)
                # gui.move(50, 50)
                # gui.genMastClicked(msg)
                globalvar.gui.desktop = QDesktopWidget()
                globalvar.gui.move((globalvar.gui.desktop.availableGeometry().width() - globalvar.gui.width()),
                                   globalvar.gui.desktop.availableGeometry().height() - globalvar.gui.height() - 10)  # 初始化位置到右下角
                # globalvar.gui.show()
                while globalvar.printwinstate:
                    QApplication.processEvents()
                    globalvar.vnfa.AsynSleep(100)
                os._exit(1)

                sys.exit(app.exec_())
            except Exception as e:
                print('PrintWin error:', e)

        def _async_raise(self, tid, exctype):
            """raises the exception, performs cleanup if needed"""
            if not inspect.isclass(exctype):
                raise TypeError("Only types can be raised (not instances)")
            res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
            if res == 0:
                raise ValueError("invalid thread id")
            elif res != 1:
                # """if it returns a number greater than one, you're in trouble,
                # and you should call it again with exc=NULL to revert the effect"""
                ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
                raise SystemError("PyThreadState_SetAsyncExc failed")

        def ExitProcessWinThread(self, win, pipe0, pipe1):
            try:
                pipe0.close()
                str = pipe1.recv()
                if str == 'hide':
                    self._async_raise(win.ident, SystemExit)
                    # globalvar.printwinstate =False
                    # win.setVisible(False)
            except EOFError:
                pass

        #@nb.jit(nogil=True, nopython=True)
        def PrintWin(self, pipe0, pipe1):
            globalvar.printwinstate = True
            win = threading.Thread(target=self.ProcessWinThread, args=(), name='PrintWin')
            win.daemon = True
            win.start()
            endwin = threading.Thread(target=self.ExitProcessWinThread, args=(win, pipe0, pipe1,),
                                      name='ExitProcessWinThread')
            endwin.daemon = True
            endwin.start()

        def CheckFinish(self, q):
            num = 0
            lastinstrumentid = ''
            listq = []
            timepath = ''
            while True:
                try:
                    QApplication.processEvents()
                    if q.empty():
                        if len(listq) > 0:
                            diffsecond = (datetime.now() - listq[1]).seconds
                            if diffsecond > 2:
                                return [lastinstrumentid, timepath]
                        time.sleep(0.3)
                    else:
                        listq = q.get(True)
                        lastinstrumentid = listq[0]
                        timepath = listq[2]

                except Exception as e:
                    print('CheckFinish error:', e)
                    if str(e) == '[WinError 232] 管道正在被关闭。':
                        num += 1
                        if num > 10:
                            print("执行完成2")
                            return [lastinstrumentid, timepath]

        def RunBackTest(self, refreshfrequency, adjustment, slippoint, period, fileid):
            self.refreshfrequency = refreshfrequency
            self.adjustment = adjustment
            self.slippoint = slippoint
            self.period = period
            fileid = fileid + self.fileidadd
            self.fileid = fileid
            # try:
            self.starttime = datetime.now()
            timepath = time.strftime("%Y%m%d%H%M", time.localtime())
            if 1:
                globalvar.pool = multiprocessing.Pool(self.processnum)
                manager = multiprocessing.Manager()

                # 父进程创建Queue，并传给各个子进程：
                globalvar.q = manager.Queue(maxsize=20)
                globalvar.pipe0, globalvar.pipe1 = Pipe()
                globalvar.pool.apply_async(self.CheckFinish, args=(globalvar.q,), callback=self.RunAgain)
                globalvar.pool.apply_async(self.PrintWin, args=(globalvar.pipe0, globalvar.pipe1,))

                self.lastinsurumentid = len(globalvar.DialogBackTestPoint.csvfile) - 1
                if True:
                    # for i in range(self.lastinsurumentid + 1):
                    if fileid > self.lastinsurumentid:
                        return
                    reportpath1 = 'backtestreport/%s' % (globalvar.DialogBackTestPoint.mainstrategyname)
                    reportpath2 = 'backtestreport/%s/%s/%s' % (
                        globalvar.DialogBackTestPoint.mainstrategyname, timepath,
                        globalvar.DialogBackTestPoint.csvfile[fileid])
                    deletepath = 'backtestreport/%s/%s' % (globalvar.DialogBackTestPoint.mainstrategyname, timepath)

                    if Path(deletepath).is_dir():
                        self.CleanDir(deletepath)

                    self.memorydatalist = []
                    globalvar.csvfile = 'backtestdata/' + globalvar.DialogBackTestPoint.csvfile[fileid]
                    linenum = len(self.memorydatalist)
                    fileinfo = os.stat(globalvar.csvfile)
                    print('csvfile:' + globalvar.csvfile)
                    print('fileinfo size: ' + str(fileinfo.st_size))
                    byteadd = 0
                    linenumadd = 0
                    if linenum == 0:
                        with open(globalvar.csvfile, 'r') as f:
                            for line in f:
                                if globalvar.DialogBackTestPoint.closestate:
                                    break
                                # if not globalvar.DialogBackTestPoint.backteststate:
                                #    break
                                globalvar.vnfa.AsynSleep(0)
                                time.sleep(0)
                                QApplication.processEvents()
                                self.memorydatalist.append(line)
                                linenumadd += 1
                                byteadd = byteadd + len(line) + 1
                                # if linenumadd%100==0:
                                globalvar.DialogBackTestPoint.bt.signal_backtest_loaddata.emit(
                                    [1, linenumadd, float(byteadd) / float(fileinfo.st_size),
                                     globalvar.DialogBackTestPoint.csvfile[fileid]])
                                # print('linenumadd: %d ,%d,%d, %d, %.2f'%(linenumadd,sys.getsizeof(line), byteadd,fileinfo.st_size,float(byteadd) / float(fileinfo.st_size)))

                        linenum = len(self.memorydatalist)

                        if adjustment == '后复权':
                            self.AdjustmentPrice_Backward(fileinfo.st_size)
                        elif adjustment == '前复权':
                            self.AdjustmentPrice_Forward(fileinfo.st_size)
                        # 合并周期
                        if period != "M1":
                            globalvar.DialogBackTestPoint.Log('开始合并周期数据')
                            self.CombinedKlineData(period, fileinfo.st_size)
                            globalvar.DialogBackTestPoint.Log('完成合并周期数据')
                    # killnum = 0
                    for key in globalvar.BackTestThreadPoint.pardict.keys():
                        if globalvar.BackTestThreadPoint.pardict[key]:
                            continue
                        parstr = key.split(',')
                        par = [int(parstr[0]), int(parstr[1]), int(parstr[2]), int(parstr[3]), int(parstr[4]),
                               int(parstr[5])]
                        self.waitsleep()
                        if globalvar.DialogBackTestPoint.closestate:
                            break
                        else:
                            # killnum += 1
                            # if killnum % 10 == 0:
                            #    continue
                            try:
                                globalvar.pool.apply_async(self.BackTestProcess, args=(
                                    globalvar.DialogBackTestPoint.strategyname,
                                    globalvar.DialogBackTestPoint.mainstrategyname,
                                    reportpath1, reportpath2, par, refreshfrequency, slippoint, period,
                                    globalvar.csvfile, linenum, fileid, globalvar.q,), callback=self.CallRusult)
                            except Exception as e:
                                print('RunBackTest error:', e)
                globalvar.pool.close()
            # except Exception as e:
            #    print('RunBackTest error:', e)

        def RunBackTestAgain(self, refreshfrequency, adjustment, slippoint, period, fileid, timepath):
            self.refreshfrequency = refreshfrequency
            self.adjustment = adjustment
            self.slippoint = slippoint
            self.period = period
            fileid = fileid + self.fileidadd
            self.fileid = fileid
            # try:
            self.starttime = datetime.now()
            if 1:
                globalvar.pool = multiprocessing.Pool(self.processnum)
                manager = multiprocessing.Manager()

                # 父进程创建Queue，并传给各个子进程：
                globalvar.q = manager.Queue(maxsize=20)
                globalvar.pipe0, globalvar.pipe1 = Pipe()
                globalvar.pool.apply_async(self.CheckFinish, args=(globalvar.q,), callback=self.RunAgain)
                globalvar.pool.apply_async(self.PrintWin, args=(globalvar.pipe0, globalvar.pipe1,))

                self.lastinsurumentid = len(globalvar.DialogBackTestPoint.csvfile) - 1
                if True:
                    # for i in range(self.lastinsurumentid + 1):
                    if fileid > self.lastinsurumentid:
                        return
                    reportpath1 = 'backtestreport/%s' % (globalvar.DialogBackTestPoint.mainstrategyname)
                    reportpath2 = 'backtestreport/%s/%s/%s' % (
                        globalvar.DialogBackTestPoint.mainstrategyname, timepath,
                        globalvar.DialogBackTestPoint.csvfile[fileid])
                    self.memorydatalist = []
                    csvfile = 'backtestdata/' + globalvar.DialogBackTestPoint.csvfile[fileid]
                    linenum = len(self.memorydatalist)
                    fileinfo = os.stat(csvfile)
                    byteadd = 0
                    linenumadd = 0
                    if linenum == 0:
                        with open(csvfile, 'r') as f:
                            for line in f:
                                if globalvar.DialogBackTestPoint.closestate:
                                    break
                                globalvar.vnfa.AsynSleep(0)
                                time.sleep(0)
                                QApplication.processEvents()
                                self.memorydatalist.append(line)
                                linenumadd += 1
                                byteadd = byteadd + len(line) + 1
                                # if linenumadd%100==0:
                                globalvar.DialogBackTestPoint.bt.signal_backtest_loaddata.emit(
                                    [1, linenumadd, float(byteadd) / float(fileinfo.st_size),
                                     globalvar.DialogBackTestPoint.csvfile[fileid]])
                        linenum = len(self.memorydatalist)
                        if adjustment == '后复权':
                            self.AdjustmentPrice_Backward(fileinfo.st_size)
                        elif adjustment == '前复权':
                            self.AdjustmentPrice_Forward(fileinfo.st_size)
                        # 合并周期
                        if period != "M1":
                            globalvar.DialogBackTestPoint.Log('开始合并周期数据')
                            self.CombinedKlineData(period, fileinfo.st_size)
                            globalvar.DialogBackTestPoint.Log('完成合并周期数据')
                    self.fileidadd = 1
                    for key in globalvar.BackTestThreadPoint.pardict.keys():
                        if globalvar.BackTestThreadPoint.pardict[key]:
                            continue
                        self.fileidadd = 0
                        parstr = key.split(',')
                        par = [int(parstr[0]), int(parstr[1]), int(parstr[2]), int(parstr[3]), int(parstr[4]),
                               int(parstr[5])]
                        self.waitsleep()
                        if globalvar.DialogBackTestPoint.closestate:
                            break
                        else:
                            try:
                                globalvar.pool.apply_async(self.BackTestProcess, args=(
                                    globalvar.DialogBackTestPoint.strategyname,
                                    globalvar.DialogBackTestPoint.mainstrategyname,
                                    reportpath1, reportpath2, par, refreshfrequency, slippoint, period,
                                    csvfile, linenum, fileid, globalvar.q,), callback=self.CallRusult)
                            except Exception as e:
                                print('RunBackTest error:', e)

                globalvar.pool.close()
            # except Exception as e:
            #    print('RunBackTest error:', e)
